home *** CD-ROM | disk | FTP | other *** search
-
- |====================================|
- | |
- | TELEMACHOS proudly presents : |
- | |
- | Part 2 of the PXD trainers - |
- | |
- | EMS-HANDLING |
- | the way to do it <g> |
- | |
- |====================================|
-
- ___---__--> The Peroxide Programming Tips <--__---___
-
- <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
-
-
- Intoduction
- -----------
-
- Hiya... I'm Telemachos of Peroxide - a new danish group (yes... we DO have
- groups in Denmark too :))) )
- In my last trainer "DOOM-walls : The technique and tricks" (which is really
- great, and I think you should leech it RIGHT away from the net :) ) I promised
- to do a trainer on the subject : Using the PC's memmory above the 640K limit
- which is set when using the standard memory-handling procedures provided with
- Turbo Pascal.
- Throughout this trainer I'll drop code in Pascal - with quite a load of asm
- code build in.
- But (as mentioned earlier.. uhmm.. like on line above this one) as most of
- the code is asm it should be easy to port to other languages like C/C++ or
- TASM (no kiddin' ?? :) ).
-
- So, this trainer won't teach you to do colorful graphic effects that'll
- impress your friends and make your girlfriend proud of you.
- It will perhaps also be a bit boring when I start talking about the PC's
- hardware-limitations and stuff...
- But I promise you - it'll be well worth the reading time anyway as it'll give
- you the key to fast computer graphic - the key to storing ALL your data in
- memory before the program executes :)
-
- So here we go.... "EMS-HANDLING : the way to do it :) "
-
-
- *************************** ATTENTION ARTISTS!!! *****************************
-
- ARE YOU AN ARTIST ?
- DO YOU DRAW VGA-BITMAPS ?
- CAN YOU DO GFX IN ALL RESOLUTIONS - 320x200x256 AND VARIOUS SVGA-MODES ?
- DO YOU WANT TO SEE YOUR WORK IN AMAZING PRODUCTIONS ?
- CAN YOU DO GAME-GFX AS WELL AS BACKGROUNDS FOR DEMOS ?
-
- IF YOU MEET THE ABOVE TERMS (or some at least :) ), THEN DROP ME (TELEMACHOS)
- A MESSAGE OR MAIL THE GROUP AT : Peroxide@image.dk
-
- ******************************************************************************
-
-
- If you want to get in contact with me, there are several ways of doing it :
-
- 1) Write me via FIDO-net : 2:235/350.22
-
- 2) E-mail me : tm@image.dk
-
- 3) Snail mail me : Kasper Fauerby
- Saloparken 226
- 8300 Odder
- Denmark
-
- 4) Call me (Voice ! ) : +45 86 54 07 60
-
-
- Get this serie from the major demo-related FTP-sites or from our own homepage
- (soon at least ;) ) : http://www.image.dk/~peroxide
- or directly from my own : http://www.image.dk/~tm
-
-
- Extended vs. expanded memory
- ----------------------------
-
- We all know that the memory above 1MB can be either Extended (XMS) or Expanded
- (EMS) memory - but why do we need theese two "different" kind of memory types ?
- Why can't it all just be MEM ???
- The awnser lies all the way back when a guy called Bill Gates sat at the
- keyboard typing away on his main project - DOS!
- At that time 1MB of mem was a HUGE amount of mem.. so the guy never gave it
- a thought that perhaps someday even 1MB of mem would'nt be enough.
- He never thought that someday HE himself would release a OS that required
- 16MB of mem - just to run!!
- So.. DOS was made with a limitation of 1MB of mem. The first 640Kb being
- conventional memory - the rest being himem.
-
- But as time went on and people started to make up more and more complicated
- programs, using more and more mem, it soon became aparent that if someone
- did'nt came up with a way of supporting more memory, then DOS would die.
- So... eventually some clever clever guys came up with the XMS and EMS
- specifications - each with it's own advantages and disadvantages.
-
- The main reason why I have chosen to descripe the use of EMS memory is, that
- EMS-memory by far is the easiest himem to use.
- Its disadvantages (which I will descripe later) lies in the page-size, but
- with some clever codin' theese problems can be solved.
-
-
- What exactly is SEGMENTS and OFFSETS ?
- ---------------------------------------
-
- DOS in real-mode is a 16bit environment. This means that DOS uses the old
- 16bit registers originating from the good ol' 8086/8088 processor.
- Well, to be able to address every single byte of memory we have in the computer
- each byte has to have a unique address.
- If we use only one register (16bit) for such an address some quick calculations
- reveals that the largest address available would be :
-
- Largest address = 2^16 = 65536
-
- Not very much ehh ?? Ie. using this model we can only address 64K of mem!!!!
- Even Bill Gates saw a problem in this and so he decided to use a few more bits
- to address the memory.
- Using 17 bits gives us a limit of 128K, 18 bits 256K, 19 bits 512Kb and finally
- the amount that Bill decided to use - namely 20 bits wich gives us a total of
- 1024 (1MB) of addressable memory.
-
- But how do you address a 20bit memory location using only 16bit registers ?
- Well.. the awnser lies in dividing the memory into MEMORY SEGMENTS.
- To address a specific address in such a segment a 16bit OFFSET is used to
- determine how far IN in the SEGMENT the information is placed. This makes each
- segment 64K big.
-
- Each SEGMENT also have a 16bit base address (fx. $a000 for the video card).
- When accessed the SEGMENT address is shifted 4 bits to the left - making it a
- 20bit value. The 16bit OFFSET address is now added to this 20bit address - the
- result being the final memory address.
- In theory a SEGMENT could begin at any given memory location, but as it's
- shifted 4 places to the left (multiplied by 16) all SEGMENT will begin at an
- address divisible by 16.
-
- To sum things up we can have 2^16 = 65536 different segments within the 1MB
- boundry set by the 20bit system.
-
- Lets take a look at the video card placed at $a000. This being a 16bit value
- we shift it 4 places to the left by multiplying it with 16. This gives us the
- memory location where the video card begin. $a000 shl 4 = $a0000 (hell... hex
- IS pretty neat huh ?? ) = 655360 bytes = 640K.
- WOW.. the card is JUST after the conventional memory :) So now you know what
- the memory from 640K to 704K does :)
-
-
- So every single byte of memory (below 1MB that is) is addressed through its
- SEGMENT and an OFFSET in this segment.
-
- As an example lets take a look at the VGA screen again. Its SEGMENT being
- $a000 all we need to know is the offset. In mode 13h the memory layout is
- lineary - ie. the first pixel being at offset 0, the second at offset 1 and so
- on. Lets say we want to plot the 256th pixel on screen (coordinates ( 256,0)).
- Then the offset will be 256 = $100 - so the address desciped in 16bit registers
- is
- pixel : $a000:$0100
-
-
- Yeah right... I knew all that - but what about EMS?
- ---------------------------------------------------
-
- EMS is - as mentioned earlier - just a name for the physical memory above the
- 1MB boundry.
- Actually this mem is only *made* EMS mem because of the LIM-specifications.
- The LIM expanded memory specifications is a software interface between the
- expanded memory manager (EMM) and the software that wishes to use the EMS
- memory. LIM supports up to 32M of EMS memory.
-
- Because the computer (still talkin' real mode) can only physical address memory
- below 1M the EMS memory is handled through a WINDOW placed in himem - that is
- between 640K and 1024K.
- This window is called the page-frame. In the page-frame is several PHYSICAL EMS
- pages - each with the size of 16K - which I'll return to later.
- The EMS memory is divided into a number of LOGICAL pages... also with a size of
- 16K.
-
- The trick is to map these LOGICAL pages into the PHYSICAL pages... and then
- address them as normal memory.
- You can look at the EMS memory as a giant piece of paper with information
- written on it - but what you actually see of this information is determined
- by the position of the "windows" in the page frame.
-
- Take a look at this diagram :
-
-
- ----------------------------- up to 32MB
- | |
- | EMS memory : |
- | |
- | divided into lots of |
- | 16K blocks... LOGICAL |
- | pages! |
- | |
- | |
- |=============================| 1024K (1MB)
- / | / / / / / / / / / / / / / / |
- / |-----------------------------| 960K
- THIS IS / | THE PAGE FRAME : |
- HIMEM! / | |
- \ | divided into 12 16K |
- \ | physical memory blocks |
- \ |-----------------------------| 768K
- \ | / / / / / / / / / / / / / / |
- |=============================| 640K
- / | |
- / | 24 16K physical pages |
- / | intended only for |
- / | operating system / |
- THIS IS / | environment |
- CONVEN- \ |-----------------------------| 256K
- TIONAL \ | / / / / / / / / / / / / / / |
- MEMORY \ | / / / / / / / / / / / / / / |
- \ | / / / / / / / / / / / / / / |
- \ |=============================| 0K
-
-
- Besides the page frame, himem is stuffed with things like the video memory and
- all sorts of devices and drivers you load with the LoadHigh and DeviceHigh
- commands in your autoexec.bat and config.sys.
- Now, this is why you have so much less himem to play with when running EMS -
- the page frame swallows quite a bit of memory :)
-
-
- Ok... Now I understand EMS - How do I code it ???
- --------------------------------------------------
-
- Well.. the EMS functions are all controlled through int 67h.
- There are LOTS of functions, but I will only descripe the most important here.
- For a complete reference to all of the functions in int 67h get a copy of the
- file ems4spec.doc which is a complete transcription of the LIM-specifications.
- It is not included here with this tuturial as it's a 450Kb text file :)
-
- I think the easiest way to understand the different basic EMS functions is to
- go through an EMS unit I have created for this tuturial. Each procedure /
- function will be explained as we go through them.
-
- [ cut here for a rip of the unit TMEMS.PAS]
-
- Unit TMEMS;
-
- INTERFACE
-
- Var Handle : integer;
- {by declaring this a public variable I assume that you will only be allocating
- EMS pages ONCE during a program.
- It saves you from having to pass the handle to a couple of functions every
- time you call them.
- But then you can't fx. allocate 10 pages at the beginning of the program -
- and then allocate 15 more later.
- If you wan't to do that you'll have to rewrite a couple of the routines so
- that the correct handle must be passed to them when called.}
-
- Function Hex_String (Number: Integer): String;
- Function EMS_AreYouThere : Boolean;
- Procedure Pagestatus(Var Total, Available: Integer);
- Procedure Allocate_Pages(Needed: Integer);
- Procedure Map_Page(Logical : Integer;Physical : byte);
- Function Get_Frame_Address : Integer;
- Procedure Deallocate_Pages;
- Function Get_Version_Number : string;
-
- IMPLEMENTATION
-
- Function Hex_String (Number: Integer): string;
- Function Hex_Char (Number: Integer): Char;
- Begin
- If Number < 10 then Hex_Char := Char (Number + 48)
- else Hex_Char := Char (Number + 55);
- end; { Function Hex_char }
-
- Var
- S: string;
- Begin
- S := '';
- S := Hex_Char ((Number shr 1) div 2048);
- Number := (((Number shr 1) mod 2048) shl 1) + (Number and 1);
- S := S + Hex_Char (Number div 256);
- Number := Number mod 256;
- S := S + Hex_Char (Number div 16);
- Number := Number mod 16;
- S := S + Hex_Char (Number);
- Hex_String := S + 'h';
- end; { Function Hex_String }
-
- {uhm... this procedure is ripped from the file ems4spec.doc }
-
-
- {***********************}
-
- Function EMS_AreYouThere : Boolean;
- Var
- EMS_Name : string[8];
- Returned_Name : string[8];
- Position : integer;
- segm : word;
-
- Begin
- Returned_Name := '';
- EMS_Name := 'EMMXXXX0'; {this is the ID string that SHOULD appear
- in the code segment of int 67h}
- asm
- mov ah,35h
- mov al,67h
- int 21h
- mov segm,es
- end;
-
- For Position := 0 to 7 do
- Returned_Name := Returned_Name + Chr (mem[segm:Position + $0A]);
-
- {This call will return the segment address where the ID string SHOULD
- be.
- If the ID string is there it'll be placed from offset $0A to $11}
-
-
- If Returned_Name = EMS_Name
- then EMS_AreYouThere := true
- else EMS_AreYouThere := false;
- end; { Function EMS_AreYouThere }
-
-
- {*******************}
-
- Procedure Pagestatus(Var Total, Available: Integer);
- Var
- HowManyInAll : word;
- HowManyAvailable : word;
- Begin
- asm
- mov ah,42h {this is EMS function nr. 42h }
- int 67h
- mov HowManyAvailable,bx
- mov HowManyInAll,dx
- end;
- Available:=HowManyAvailable;
- Total:=HowManyInAll;
- end; { Function Pagestatus }
-
-
- {This Procedure is nice when you want to know if there is enough free EMS
- memory to run your program.}
-
-
- {*************}
-
- Procedure Allocate_Pages(Needed: Integer);
- Assembler;
- asm
- mov ah,43h {this is EMS function nr. 43h}
- mov bx,[Needed]
- int 67h
- mov [handle],dx {NOT very nice... but heck... I like it this way}
- end; { Function Allocate_Pages }
-
- {When you run this procedure you allocate a certain amount of EMS pages.
- A handle is then assigned to these pages. Those of you who code TASM know of
- handles from file handling routines.
- But those of you who just use Pascal are'nt used to having a number assigned
- to a file or a piece of memory. Well.. its basicly the same thing as when you
- use the Assign comand in TP. Here you assign a string - namely the filename -
- to a var of the type : file (or file of bla bla bla). Later you use this var
- when you want to manipulate with the file.
- Same thing here - don't think about it.}
-
-
- {*****************}
-
- procedure Map_Page(Logical : Integer;Physical : byte);
- Assembler;
- asm
- mov ah,44h {EMS function nr. 44h}
- mov dx,[handle] {humm... NO comments :) }
- mov bx,[logical]
- mov al,[Physical]
- int 67h
- end; { Function Map_Page }
-
- {This procedure sets a window in the page frame to a certain logical page
- in EMS memory.
- From now on, when you manipulate with the physical page in the page frame
- you manipulate with the mapped logical page in EMS}
-
- {****************}
-
-
- Function Get_Frame_Address : Integer;
- Assembler;
- asm
- mov ah,41h {EMS function nr. 41h}
- int 67h
- mov ax,bx
- end;
-
- {This function returns the segment address of the page frame.
- Now this one is VERY!! important. When mapping logical pages into physical
- pages the programmer needs to know where to address the physical pages.
- Each physical page in the page frame has its own segement address.
- Physical page nr. 0 has THE SAME ADDRESS AS THE PAGE FRAME.
- From then on the physical pages are $400 (1Kb) apart - ie :
- (say that the page frame address is $D000 - it often is )
-
- physical page nr. segment address
- 0 $D000
- 1 $D400
- 2 $D800
- 3 $DC00
- 4 $E000
- }
-
- {*****************}
-
- Procedure Deallocate_Pages;
- Assembler;
- asm
- mov ah,45h
- mov dx,[handle] {humm... keeps popping up everywhere }
- int 67h
- end; { Procedure Deallocate_Pages }
-
- {This returns the allocated EMS pages to the memory pool.
- If you don't call this when closing a program down the EMS
- memory will be useless to all other programs too }
-
-
- {************}
-
- Function Get_Version_Number : String;
- Var
- Integer_Part, Fractional_Part: byte;
-
- Begin
- asm
- mov ah,46h
- int 67h
- cmp ah,0
- jne @error
- mov bl,al
- shr bl,4
- add bl,48
- mov Integer_part,bl
- mov bl,al
- and bl,$F
- add bl,48
- mov Fractional_Part,bl
- @error :
- end;
- Get_version_number:=chr(Integer_part)+'.'+chr(Fractional_part);
- end; { Function Get_Version_Number }
-
- {Ripped from ems4spec.doc - well.. the idea that is, rewritten to asm by ME <G>}
-
-
- [ end unit code ]
-
-
- Writing a program that uses EMS memory
- ---------------------------------------
- OK.. when writing a program that uses EMS memory there are certain things that
- you must ALWAYS do.
-
- 1) Initialize the EMM manager. Call EMS_AreYouThere to see if EMS is available.
-
- 2) Check if all the pages needed are available in the current system. You'll
- have to try and calculate how many EMS pages your program is going to use.
-
- 3) Allocate these pages and (if you don't use my unit) store the EMS handle in
- some logically named variable.. like : "EMS_handle" :)
-
- 4) Get the address of the PAGE FRAME. Store this address in a variable - I
- personally likes to use the name FADDR (frame address).
- When ever you want to write to EMS memory you do the following :
-
- Mem[Faddr+Phys_PageNr * $400 : offset_in_page] := value_to_be_stored;
-
- Voila! Now you have written to the LOGICAL EMS page that was mapped in
- Phys_PageNr.
- Often You'll find that you only have to use Physical Page nr 0...
- If this is the case in your program simply use
-
- Mem[Faddr: offset_in_page] := Value_to_be_stored;
-
- In my Eye Of The Beholder demo from tuturial 1 I only use ONE physical page.
-
- 5) Go ahead and use the memory. When writing to EMS map the correct page into
- a physical page and write to this one - when reading from an EMS page map
- the page to the physical page and read from this one.
- It really IS as simple as this!
-
- 6) When you are through using the EMS memory don't forget to deallocate the
- used pages. Otherwise they will be unuseable by the system in any other
- applications.
-
-
-
-
- Advantages / Disadvantages
- ---------------------------
-
- The main advantage of using EMS memory is the ease of coding for it :)
- Really - with a few routines as those listed earlier in this tuturial you can
- code applications using up to 32MB of memory as easy as if it were all
- conventional memory. Play with the routines for an hour or so.... and you'll
- master EMS.
- Also EMS is fairly quick. Only an interrupt is required for mapping a LOGICAL
- EMS page into addressable memory. And with multiple physical pages available
- and some clever coding / structuring there should'nt be to many swaps in the
- program.
- Those of you who want to develop futher routines for handling EMS routines
- should take a look at the file ems4spec.doc - many more complicated functions
- are available through int 67h. Fx. I could mention that it IS possible to map
- multiple pages at the same time....
-
- The main disadvantage of EMS memory is the page size. It really SUCK that an
- EMS pages originally was defined as 16K of memory. Why not 64K so that we
- could fit an entire segment into one page.
- As graphical programmers one of the first uses for EMS memory that we think of
- is storing graphic (well... I did anyway). Here a page size of 64K would be
- really cool as long as we stay in mode 13h. In that case we could store an
- entire screen in one EMS page...
- Well... unfortunately EMS pages is only 16K so we'll have to think of some
- other uses. One could split the screen up into 4 16K pieces... and then use
- 4 EMS pages pr. screen. But this is a little awkward as numerous interrupt
- calls must be made to map all four EMS pages needed to store the image.
- And when the image is to be used numerous physical_pages must be used - or the
- moving of data to the videocard must be split down into 4 parts.... one for
- each EMS page used.
-
- But fortunately lots of other datastructures fit into a 16K block of memory.
- Textures fx. is typically 64X64 or 128X128 pixels in size - making them take
- up 4K or 16K of memory.
- In my 3d-world each level supports up to 100 different textures - each of the
- size 128X128. It would be far to slow to load them from disk when they were to
- be used in runtime. But 100 textures of 16K of mem each... they take up 1.6MB
- of memory!
- Also each level supports up to 20 different monsters using 5 frames (128X128)
- each to animate movement - that's 100 16K blocks more!
- So all in all my game takes up 3.2MB of memory - I could'nt have done it
- without EMS memory.
-
- So - sprites in general, smaller bitmaps that does'nt take up the entire
- screen, lenses in demos, phongmaps, data structures for 3d objects - you name
- it.
- All those smaller structures often fit into an EMS page. When coding for EMS
- it is often required that you think about your structures when defining them.
- Perhaps you could split up some of your BIG records into several smaller ones ?
-
-
- Last remarks
- -------------
-
- Well, that's about all for now.
- Hope you found this doc useful - and BTW : If you DO make anything public using
- these techniques please mention me in your greets or where ever you se fit.
- I DO love to see my name in a greeting :=)
-
- What to do next??? Humm... I think I'll do something a little more colorfull
- next time - otherwise I'll just scare of my readers :)
- One guy requested bitmap rotation - another would like some more 3d-stuff...
- But one of these days I'm planning on doing a doc on interrupts - and how to
- use them. Comments ??
-
- If you have any good ideas for a subject you wish to see a tuturial on please
- mail me. If I like the idea (and know anything about it :) ) I'll write a
- tut on it.
-
- Humm... yeah - while I remember it.
- These docs will soon be available through my very own homepage (linked to our
- group homepage) so check out the following addresses :
-
-
- Peroxide Homepage : http://www.image.dk/~peroxide (this one is up by now)
- Telemachos' Page : http://www.image.dk/~tm (SHOULD be up when you
- read this :) )
-
-
- Keep on coding and CuL8'er M8's
-
- Telemachos - April '97.